package com.tydic.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tydic.borderer.domain.BorderAgent;
import com.tydic.borderer.domain.BordererInfo;
import com.tydic.borderer.mapper.BorderAgentMapper;
import com.tydic.borderer.service.IBordererInfoService;
import com.tydic.common.core.domain.model.LoginUser;
import com.tydic.common.core.enums.*;
import com.tydic.common.core.exception.api.ApiException;
import com.tydic.common.core.utils.RMBUpLowe;
import com.tydic.common.core.utils.ReturnUrlUtil;
import com.tydic.common.redis.constant.RedisKey;
import com.tydic.common.redis.utils.RedisUtils;
import com.tydic.common.satoken.utils.LoginHelper;
import com.tydic.common.web.domain.FileItem;
import com.tydic.common.web.domain.bo.DetailBo;
import com.tydic.common.web.domain.bo.IdBo;
import com.tydic.common.web.utils.ReplaceWordUtil;
import com.tydic.enterprise.domain.Enterprise;
import com.tydic.enterprise.mapper.EnterpriseMapper;
import com.tydic.enterprise.service.IEnterpriseService;
import com.tydic.order.domain.Order;
import com.tydic.order.domain.OrderContract;
import com.tydic.order.domain.OrderSettlement;
import com.tydic.order.domain.bo.OrderBatchBo;
import com.tydic.order.domain.bo.OrderReceiptBo;
import com.tydic.order.domain.bo.QueryOrderBo;
import com.tydic.order.domain.request.AgainHistoryByPageReq;
import com.tydic.order.domain.request.CheckSelectReq;
import com.tydic.order.domain.request.PlaceOrderRequest;
import com.tydic.order.domain.response.AppOrderResult;
import com.tydic.order.domain.response.CheckSelectResp;
import com.tydic.order.domain.vo.PlaceOrder;
import com.tydic.order.enums.OrderStatus;
import com.tydic.order.exception.OrderException;
import com.tydic.order.mapper.OrderContractMapper;
import com.tydic.order.mapper.OrderMapper;
import com.tydic.order.mapper.OrderSettlementMapper;
import com.tydic.order.service.IOrderContractService;
import com.tydic.order.service.IOrderService;
import com.tydic.product.domain.CarNumber;
import com.tydic.product.domain.Product;
import com.tydic.product.enums.ProductGroup;
import com.tydic.product.mapper.ProductMapper;
import com.tydic.product.service.ICarNumberService;
import com.tydic.product.service.IProductService;
import com.tydic.product.utils.ProductCalculateUtils;
import com.tydic.system.domain.Account;
import com.tydic.system.domain.Company;
import com.tydic.system.domain.ContractTemplate;
import com.tydic.system.domain.req.*;
import com.tydic.system.domain.resp.CreateAndPushResponse;
import com.tydic.system.domain.resp.DocDownloadResponse;
import com.tydic.system.domain.resp.UnwantedAuthSignStatusResponse;
import com.tydic.system.service.IContractTemplateService;
import com.tydic.system.service.IFddService;
import com.tydic.system.service.ISysMessageService;
import com.tydic.system.service.ISysOssService;
import com.tydic.workflow.service.IPurchaseOrderService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class OrderServiceImpl implements IOrderService {
    private final OrderMapper orderMapper;
    private final IOrderContractService orderContractService;
    private final IFddService fddService;
    private final OrderContractMapper orderContractMapper;
    private final ICarNumberService carNumberService;
    private final IProductService productService;
    private final IBordererInfoService bordererInfoService;
    private final BorderAgentMapper borderAgentMapper;
    private final ProductMapper productMapper;
    private final ISysMessageService messageService;
    private final IPurchaseOrderService purchaseOrderService;
    private final IEnterpriseService enterpriseService;
    private final EnterpriseMapper enterpriseMapper;
    private final OrderSettlementMapper orderSettlementMapper;
    private final IContractTemplateService contractTemplateService;
    private final ISysOssService sysOssService;
    @Value("${fdd.returnUrlPrefix}")
    private String returnUrlPrefix;

    @Override
    public Page<Order> getOrderByPage(QueryOrderBo bo) {
        return orderMapper.selectPage(bo.build(), buildLambdaQueryWrapper(bo));
    }

    private LambdaQueryWrapper<Order> buildLambdaQueryWrapper(QueryOrderBo bo) {
        LambdaQueryWrapper<Order> lqw = Wrappers.lambdaQuery(Order.class);
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getOrderStatus()) && !CharSequenceUtil.equals(bo.getOrderStatus(), OrderStatus.ALL.getStatus()), Order::getOrderStatus, bo.getOrderStatus());
        lqw.like(CharSequenceUtil.isNotBlank(bo.getOrderCode()), Order::getOrderCode, bo.getOrderCode());
        lqw.like(CharSequenceUtil.isNotBlank(bo.getProductTitle()), Order::getProductTitle, bo.getProductTitle());
        lqw.like(CharSequenceUtil.isNotBlank(bo.getCompanyName()), Order::getEnterpriseName, bo.getCompanyName());
        lqw.like(CharSequenceUtil.isNotBlank(bo.getBordererInfoName()), Order::getBordererInfoName, bo.getBordererInfoName());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getCompanySign()), Order::getCompanySign, bo.getCompanySign());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBordererSign()), Order::getBordererSign, bo.getBordererSign());
        lqw.like(CharSequenceUtil.isNotBlank(bo.getDeclarationNumber()), Order::getDeclarationNumber, bo.getDeclarationNumber());
        lqw.like(CharSequenceUtil.isNotBlank(bo.getBordererGroup()), Order::getBordererGroup, bo.getBordererGroup());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getParentOrderId()), Order::getParentOrderId, bo.getParentOrderId());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getGroupStatus()), Order::getGroupStatus, bo.getGroupStatus());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBordererInfoId()), Order::getBordererInfoId, bo.getBordererInfoId());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBorderAgentId()), Order::getBorderAgentId, bo.getBorderAgentId());
        lqw.in(CollUtil.isNotEmpty(bo.getIds()), Order::getId, bo.getIds());
        lqw.orderByDesc(Order::getCreateDate);
        return lqw;
    }

    private LambdaQueryWrapper<Order> buildLambdaQueryWrapper(Order bo) {
        LambdaQueryWrapper<Order> lqw = Wrappers.lambdaQuery(Order.class);
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getOrderStatus()), Order::getOrderStatus, bo.getOrderStatus());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getOrderCode()), Order::getOrderCode, bo.getOrderCode());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getProductTitle()), Order::getProductTitle, bo.getProductTitle());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBordererInfoName()), Order::getBordererInfoName, bo.getBordererInfoName());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getCompanySign()), Order::getCompanySign, bo.getCompanySign());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBordererSign()), Order::getBordererSign, bo.getBordererSign());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getDeclarationNumber()), Order::getDeclarationNumber, bo.getDeclarationNumber());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBordererGroup()), Order::getBordererGroup, bo.getBordererGroup());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getParentOrderId()), Order::getParentOrderId, bo.getParentOrderId());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBordererInfoId()), Order::getBordererInfoId, bo.getBordererInfoId());
        lqw.eq(CharSequenceUtil.isNotBlank(bo.getBorderAgentId()), Order::getBorderAgentId, bo.getBorderAgentId());
        return lqw;
    }

    private List<Order> findList(QueryOrderBo bo) {
        return orderMapper.selectList(buildLambdaQueryWrapper(bo));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<String> signOrder(OrderBatchBo bo) {
        List<String> signUrls = new ArrayList<>();
        if (bo.isEnable()) {
            bo.getIds().forEach(id -> {
                Order order = orderMapper.selectById(id);
                OrderStatus orderStatus = OrderStatus.of(order.getOrderStatus());
                if (orderStatus == OrderStatus.CANCEL) {
                    throw new OrderException("订单已取消!");
                }
                ProductGroup productGroup = ProductGroup.of(order.getGroupStatus());
                if (productGroup == ProductGroup.PARENT) {
                    QueryOrderBo bo1 = new QueryOrderBo();
                    bo1.setParentOrderId(order.getOrderCode());
                    bo1.setOrderStatus(OrderStatus.WAIT_SIGN.getStatus());
                    List<Order> orders = findList(bo1);
                    for (Order item : orders) {
                        List<String> signUrlsChild = getSignUrls(item);
                        signUrls.addAll(signUrlsChild);
                    }
                } else {
                    List<String> signUrlsDefault = getSignUrls(order);
                    signUrls.addAll(signUrlsDefault);
                }
            });

        }
        return signUrls;
    }

    private List<String> getSignUrls(Order order) {
        OrderStatus orderStatus = OrderStatus.of(order.getOrderStatus());
        LoginUser currentUser = LoginHelper.getLoginUser();
        List<String> signUrls = new ArrayList<>();
        //填充合同，并上传
        //根据订单类型查询合同模板
        if (OrderStatus.WAIT_SIGN == orderStatus) {
            OrderContract byOrderCode = orderContractService.getByOrderCode(order.getOrderCode());
            if (StrUtil.equalsAny(currentUser.getUserType(), UserTypeEnum.BORDERER.getUserType(), UserTypeEnum.BORDERER_AGENT.getUserType())) {
                if (byOrderCode == null) {
                    throw new ApiException("当前合同还未发起签署，请稍后");
                } else {
                    //边民
                    if (byOrderCode.getBorderSignUrl() != null && byOrderCode.getBordererSign().equals(SignStatusEum.UNSIGNED.getStatus())) {
                        BordererInfo bordererInfoByUserCode = bordererInfoService.getBordererInfoById(byOrderCode.getBordererInfoId());
                        Account account = fddService.getAccountByMobile(bordererInfoByUserCode.getPhoneNumber());
                        SeachUnwantedAuthSignRequest borderAuthSign = new SeachUnwantedAuthSignRequest();
                        borderAuthSign.setAuthorizerFlag(AuthTypeEnum.BORDERER.getType());
                        borderAuthSign.setAuthorizerTargetId(account.getAccountId());
                        UnwantedAuthSignStatusResponse borderAuthSignResponse = fddService.searchUnwantedAuthSignStatus(borderAuthSign);
                        //如果已经开通免验证签 - 手动免验证签签署
                        if (borderAuthSignResponse != null && NumberUtil.equals(borderAuthSignResponse.getStatus(), UnwantedAuthSignEnum.EFFECT.getType())) {
                            //记录未开通边民代表的姓名，并返回。
                            //完成手动免验证签签署
                            FinishUnwantedAuthSignRequest finishUnwantedAuthSignRequest = new FinishUnwantedAuthSignRequest();
                            finishUnwantedAuthSignRequest.setNotifyNo(byOrderCode.getBordererSignNotify());
                            finishUnwantedAuthSignRequest.setDocId(byOrderCode.getDocId());
                            fddService.finishUnwantedAuthSign(finishUnwantedAuthSignRequest);
                        } else {
                            //如果没开通那就要更新获取签署链接 -> 手动签署
                            signUrls.add(byOrderCode.getBorderSignUrl());
                        }
                    } else {
                        throw new ApiException("当前合同还在发起签署中，请稍后");
                    }
                }
            }
            if (StrUtil.equals(UserTypeEnum.ENTERPRISE.getUserType(), currentUser.getUserType())) {
                if (byOrderCode != null && byOrderCode.getBordererSign().equals(SignStatusEum.UNSIGNED.getStatus())) {
                    SeachUnwantedAuthSignRequest borderAuthSign = new SeachUnwantedAuthSignRequest();
                    borderAuthSign.setAuthorizerFlag(AuthTypeEnum.ENTERPRISE.getType());
                    borderAuthSign.setAuthorizerTargetId(byOrderCode.getCompanyAccountId());
                    UnwantedAuthSignStatusResponse borderAuthSignResponse = fddService.searchUnwantedAuthSignStatus(borderAuthSign);
                    if (borderAuthSignResponse != null && NumberUtil.equals(borderAuthSignResponse.getStatus(), UnwantedAuthSignEnum.EFFECT.getType())) {
                        //记录未开通边民代表的姓名，并返回。
                        //完成手动免验证签签署
                        FinishUnwantedAuthSignRequest finishUnwantedAuthSignRequest = new FinishUnwantedAuthSignRequest();
                        finishUnwantedAuthSignRequest.setNotifyNo(byOrderCode.getCompanySignNotify());
                        finishUnwantedAuthSignRequest.setDocId(byOrderCode.getDocId());
                        fddService.finishUnwantedAuthSign(finishUnwantedAuthSignRequest);
                    } else {
                        signUrls.add(byOrderCode.getCompanySignUrl());
                    }

                } else {
                    //查询缓存，如有则标明当前订单正在签署中
//                            String orderCode = RedisUtil.get(order.getOrderCode());
//                            if (orderCode == null) {
//                                RedisUtil.set(order.getOrderCode(), order.getOrderCode(), Duration.(1));
                    uploadAndUpdate(order.getId());
                    //验证合同是否上传成功，可以签署 :更具orderCode查询OrderContract（js_sys_order_contract）表中的upload_file_id是否存在即可
                    OrderContract orderContract = orderContractService.getByOrderCode(order.getOrderCode());

                    //签署合同
                    if (ObjectUtil.isNotEmpty(orderContract) && orderContract.getUploadFileId() != null) {


                        //企业是否免验证签
                        String authSignStatus = EnableEnum.DISABLE.getStatus();
                        SeachUnwantedAuthSignRequest borderAuthSign = new SeachUnwantedAuthSignRequest();
                        borderAuthSign.setAuthorizerFlag(AuthTypeEnum.ENTERPRISE.getType());
                        borderAuthSign.setAuthorizerTargetId(orderContract.getCompanyAccountId());
                        UnwantedAuthSignStatusResponse borderAuthSignResponse = fddService.searchUnwantedAuthSignStatus(borderAuthSign);
                        if (borderAuthSignResponse != null && NumberUtil.equals(borderAuthSignResponse.getStatus(), UnwantedAuthSignEnum.EFFECT.getType())) {
                            authSignStatus = EnableEnum.ENABLE.getStatus();

                        }
                        boolean flg = createAndPush(order.getOrderCode(), order.getId(), authSignStatus);
                        if (!flg)
                            throw new ApiException("创建签署失败");
                        //获取签署链接（未来接入短信功能）
                        String signUrl = getSignUrl(order.getOrderCode());
                        if (signUrl != null && authSignStatus.equals(EnableEnum.DISABLE.getStatus())) {
                            signUrls.add(signUrl);
                        }
                    }
                }
            }
        } else {
            throw new ApiException("订单已签署!");
        }
        return signUrls;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void payOrder(OrderBatchBo request) {
        if (request.isEnable()) {
            request.getIds().forEach(id -> {
                Order order = checkOrderExist(id);

                if (!CharSequenceUtil.equals(OrderStatus.WAIT_PAY.getStatus(), order.getOrderStatus())) {
                    throw new ApiException("商品不是待付款状态!");
                }
                // 付款后，下一步待发货
                order.setOrderStatus(OrderStatus.WAIT_DELIVER.getStatus());
                orderMapper.updateById(order);
                BordererInfo bordererAgent = bordererInfoService.getBordererInfoById(order.getBorderAgentId());
                Map<String, Object> params = new HashMap<>();
                params.put("bordererAgent", bordererAgent.getUserCode());
                purchaseOrderService.submit(order.getProcInstId(), params, "已付款", true);
                updateChildrenOrderStatus(order.getId(), OrderStatus.WAIT_DELIVER);
                messageService.handleMessage(MessageCategoryEnum.WAIT_PAY, order.getId());
                messageService.insertMessageHandler(MessageCategoryEnum.CONFIRM_DELIVER, order.getId(), "订单待发货", String.format("订单%s已完成付款，等待卖家发货", order.getId()), bordererAgent.getUserCode());
                RedisUtils.deleteObject(RedisKey.PAY_ORDER.createRedisKey(order.getId()));
            });
        }
    }

    /**
     * 验证订单是否存在
     *
     * @param id 订单ID
     * @return 订单信息
     */
    private Order checkOrderExist(String id) {
        Order order = orderMapper.selectById(id);
        if (ObjectUtil.isNull(order)) {
            throw new ApiException("订单不存在!");
        }
        return order;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void modifyReceipt(OrderReceiptBo modifyReceiptRequest) {
        Order order = checkOrderExist(modifyReceiptRequest.getId());
        if (CharSequenceUtil.equals(order.getStatus(), OrderStatus.CANCEL.getStatus())) {
            throw new ApiException("该订单已被取消");
        }
        if (!CharSequenceUtil.equals(order.getStatus(), OrderStatus.WAIT_SIGN.getStatus())) {
            throw new ApiException("订单已完成支付，无法修改收货信息");
        }
        BeanUtil.copyProperties(modifyReceiptRequest, order, "id", "carNumbers");
        orderMapper.insertOrUpdate(order);
        carNumberService.clear(order.getId(), CarNumberBusinessTypeEnum.ORDER.getType());
        ArrayList<String> carNumbers = modifyReceiptRequest.getCarNumbers();
        carNumberService.save(order.getId(), CarNumberBusinessTypeEnum.ORDER.getType(), carNumbers);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void confirmDeliverProduct(OrderBatchBo request) {
        if (request.isEnable()) {
            request.getIds().forEach(id -> {
                Order order = checkOrderExist(id);
                if (!CharSequenceUtil.equals(OrderStatus.WAIT_DELIVER.getStatus(), order.getOrderStatus())) {
                    throw new ApiException("商品不是待发货状态!");
                }
                // 确认发货后，下一步等待收货
                order.setOrderStatus(OrderStatus.WAIT_TAKE_OVER.getStatus());
                orderMapper.updateById(order);
                purchaseOrderService.submit(order.getProcInstId(), "已发货", true);
                updateChildrenOrderStatus(order.getId(), OrderStatus.WAIT_TAKE_OVER);
                carNumberService.updateAllow(order.getProductId(), CarNumberBusinessTypeEnum.PRODUCT.getType());
                messageService.handleMessage(MessageCategoryEnum.CONFIRM_DELIVER, order.getId());
                Enterprise enterprise = enterpriseMapper.selectById(order.getEnterpriseId());
                messageService.insertMessageHandler(MessageCategoryEnum.CONFIRM_RECEIPT, order.getId(), "订单待收货", String.format("订单%s已完成发货，等待买家收货", order.getId()), enterprise.getUserCode());
            });
        }
    }

    private void updateChildrenOrderStatus(String id, OrderStatus orderStatus) {
        List<Order> children = findByParentOrderId(id);
        children.forEach(item -> {
            item.setOrderStatus(orderStatus.getStatus());
        });
        orderMapper.updateBatchById(children);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void confirmTakeGoods(OrderBatchBo request) {
        if (request.isEnable()) {
            request.getIds().forEach(id -> {
                Order order = checkOrderExist(id);

                if (!CharSequenceUtil.equals(OrderStatus.WAIT_TAKE_OVER.getStatus(), order.getOrderStatus())) {
                    throw new ApiException("订单不是待收货状态!");
                }

                if (ProductGroupEnum.CHILD.equalsStatus(order.getGroupStatus())) {
                    throw new ApiException("子订单禁止收货!");
                }

                order.setOrderStatus(OrderStatus.TAKE_OVER.getStatus());
                orderMapper.updateById(order);
                carNumberService.updateAllow(order.getId(), CarNumberBusinessTypeEnum.ORDER.getType());
                purchaseOrderService.submit(order.getProcInstId(), "收货", true);
                updateChildrenOrderStatus(order.getId(), OrderStatus.TAKE_OVER);
                messageService.handleMessage(MessageCategoryEnum.CONFIRM_RECEIPT, order.getId());
                messageService.insertNeedHandler(MessageCategoryEnum.WAIT_SETTLE, order.getId(), "订单待结算", String.format("订单%s已完成交易，请处理结算费用", order.getId()));
            });
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelOrder(OrderBatchBo request) {
        if (request.isEnable()) {
            request.getIds().forEach(this::cancelOrder);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void invoice(OrderBatchBo bo) {
        throw new ApiException("进行中！");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void settlementOrder(IdBo request) {
        Order order = checkOrderExist(request.getId());

        if (CharSequenceUtil.equals(OrderStatus.CANCEL.getStatus(), order.getOrderStatus())) {
            throw new ApiException("订单已取消!");
        }

        if (CharSequenceUtil.equals(OrderStatus.COMPLETE.getStatus(), order.getOrderStatus())) {
            throw new ApiException("订单已完成!");
        }

        if (CharSequenceUtil.equals(OrderStatus.WAIT_SIGN.getStatus(), order.getOrderStatus())) {
            throw new ApiException("订单未签署!");
        }

        if (!CharSequenceUtil.equals(OrderStatus.TAKE_OVER.getStatus(), order.getOrderStatus())) {
            throw new ApiException("订单未收货!");
        }

        if (ProductGroupEnum.CHILD.equalsStatus(order.getGroupStatus())) {
            throw new ApiException("子订单禁止结算!");
        }

        order.setOrderStatus(OrderStatus.COMPLETE.getStatus());
        orderMapper.updateById(order);

        // 结算所有子订单
        findByParentOrderId(order.getId()).forEach(item -> {
            item.setOrderStatus(OrderStatus.COMPLETE.getStatus());
            orderMapper.updateById(item);
            BordererInfo bordererAgent = bordererInfoService.getBordererInfoById(item.getBorderAgentId());
            BordererInfo borderer = bordererInfoService.getBordererInfoById(item.getBordererInfoId());
            insertOrderSettle(item.getId(), ProductCalculateUtils.stripTrailingZerosString(item.getServiceCharge()), OrderSettlementTypeEnum.SERVICE_CHARGE, "平台账户");
            insertOrderSettle(item.getId(), ProductCalculateUtils.stripTrailingZerosString(item.getTaxation()), OrderSettlementTypeEnum.TAXES, "东兴市税务局");
            insertOrderSettle(item.getId(), ProductCalculateUtils.stripTrailingZerosString(item.getCost()), OrderSettlementTypeEnum.COST, String.format("%s(边民代表)", bordererAgent.getName()));
            insertOrderSettle(item.getId(), ProductCalculateUtils.stripTrailingZerosString(item.getProfit()), OrderSettlementTypeEnum.PROFIT, String.format("%s(边民)", borderer.getName()));
        });

        purchaseOrderService.submit(order.getProcInstId(), "订单结算", true);

        messageService.handleMessage(MessageCategoryEnum.WAIT_SETTLE, request.getId());

    }

    private void insertOrderSettle(String orderId, String amount, OrderSettlementTypeEnum orderSettlementTypeEnum, String source) {
        OrderSettlement orderSettlement = new OrderSettlement();
        orderSettlement.setOrderId(orderId);
        orderSettlement.setAmount(amount);
        orderSettlement.setType(orderSettlementTypeEnum.getType());
        orderSettlement.setSource(source);
        orderSettlement.setCreateDate(DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN));
        orderSettlementMapper.insertOrUpdate(orderSettlement);
    }

    /**
     * 填充合同信息
     *
     * @param order
     * @param templateFileId
     * @return
     */
    private FileItem fillContract(Order order, String templateFileId) {

        Map<String, Object> data = new HashMap<>();
        Map<String, Object> picData = new HashMap<>();

        //查询企业信息
        Enterprise enterprise = enterpriseMapper.selectById(order.getEnterpriseId());

        //甲方
        if (order.getEnterpriseName() != null) {
            data.put("${partyA}", order.getEnterpriseName());
        } else {
            throw new ApiException("甲方姓名不能为空");
        }
        if (order.getReceiverName() != null) {
            data.put("${buyer}", order.getReceiverName());
        } else {
            throw new ApiException("买方信息不能为空");
        }

        //法定代表人或委托人
        if (enterprise.getLegalRepresentative() != null) {
            data.put("${deputyA}", enterprise.getLegalRepresentative());
        } else {
            throw new ApiException("法定代表人或委托人不能为空");
        }

        //TODO 纳税人识别号

        if (enterprise.getEnterpriseCode() != null) {
            data.put("${idenNo}", enterprise.getEnterpriseCode());
        } else {
            throw new ApiException("纳税人识别号不能为空");
        }
        //电话
        if (enterprise.getPhoneNumber() != null) {
            data.put("${mobile}", enterprise.getPhoneNumber());
        } else {
            throw new ApiException("电话不能为空");
        }
        //开户银行
        if (enterprise.getBankName() != null) {
            data.put("${openBank}", enterprise.getBankName());
        } else {
            throw new ApiException("开户银行不能为空");
        }
        //帐号
        if (enterprise.getBankAccount() != null) {
            data.put("${account}", enterprise.getBankAccount());
        } else {
            throw new ApiException("银行卡号不能为空");
        }
        //地址
        if (enterprise.getBusinessLicenseLocation() != null) {
            data.put("${address}", enterprise.getBusinessLicenseLocation());
        } else {
            throw new ApiException("地址信息不能为空");
        }

        //边民信息
        BordererInfo bordererInfo = bordererInfoService.getBordererInfoById(order.getBordererInfoId());
        //乙方
        if (order.getBordererInfoName() != null) {
            data.put("${partyB}", order.getBordererInfoName());
        } else {
            throw new ApiException("乙方信息不能为空");
        }

        //乙方法定代表人 - （如果不是普通订单，填边民代表）
        String deputyB = bordererInfo.getEnterpriseName();
        String parentOrderId = order.getParentOrderId();
        if (parentOrderId != null) {
            Order entity = orderMapper.selectById(parentOrderId);
            if (entity != null) {
                deputyB = entity.getBordererInfoName();
            }
        }
        data.put("${deputyB}", deputyB);

        //卖方
        if (order.getBordererInfoName() != null) {
            data.put("${seller}", order.getBordererInfoName());
        } else {
            throw new ApiException("卖方姓名不能为空");
        }

        //身份证号
        if (bordererInfo.getIdCardNumber() != null) {
            data.put("${idCardNo}", bordererInfo.getIdCardNumber());
        } else {
            throw new ApiException("身份证号不能为空");
        }


        if (order.getReceiverTime() != null) {
            String receiverTime = order.getReceiverTime();
            String[] split = receiverTime.split("-");
            //交货时间delivery
            data.put("${deliveryYear}", split[0]);
            data.put("${deliveryMonth}", split[1]);
            data.put("${deliveryDay}", split[2]);
        } else {
            throw new ApiException("交货时间不能为空");
        }


        /**
         * 采购品种、规格、采购数量、价格
         */
        //商品标题
        Product product1 = productMapper.selectById(order.getProductId());
        if (product1 != null) {
            data.put("${goodsTitle}", product1.getTitle());
        } else {
            throw new ApiException("采购品种不能为空");
        }
        //商品名称
        if (order.getProductDataName() != null) {
            data.put("${goodsName}", order.getProductDataName());
        } else {
            throw new ApiException("采购品种不能为空");
        }

        //规格型号
        if (order.getProductDataType() != null) {
            data.put("${goodsType}", order.getProductDataType());
        } else {
            throw new ApiException("采购规格型号不能为空");
        }

        //单价
        if (order.getAmount() != null) {
            data.put("${price}", order.getAmount());
        } else {
            throw new ApiException("采购单价不能为空");
        }

        //TODO 质量单位 未确定
        if (order.getProductQuantity() != null) {
            data.put("${weight}", order.getProductQuantity() + "");
        } else {
            throw new ApiException("重量不能为空");
        }

        //总额（元）
        if (order.getAmount() != null) {
            data.put("${total}", order.getAmount());
        } else {
            throw new ApiException("总额不能为空");
        }

        //合计
        if (order.getAmount() != null) {
            data.put("${totalPrice}", order.getAmount());
        } else {
            throw new ApiException("合同合计金额不能为空");
        }

        //合计金额人民币(大写)
        if (order.getAmount() != null) {
            data.put("${rmb}", RMBUpLowe.convertNum(order.getAmount()));
        } else {
            throw new ApiException("合计金额人民币不能为空");
        }


        //合同编号中的日期和编号
        String format = DateUtil.format(new Date(), "yyyy-MM-dd");
        data.put("${date}", format);
        data.put("${num}", "001");

        //签订时间
        String[] formatStr = format.split("-");
        data.put("${year}", formatStr[0]);
        data.put("${month}", formatStr[1]);
        data.put("${day}", formatStr[2]);

        ContractTemplate contractTemplate = new ContractTemplate();
        contractTemplate.setTemplateType("0");
        contractTemplate.setTemplateStatus(ContractStatusEnum.USING.getStatus());
        List<ContractTemplate> list = contractTemplateService.queryList(contractTemplate);
        if (CollUtil.isEmpty(list)) {
            throw new ApiException("请联系管理员上传购销合同模板");
        }
        File file = sysOssService.getFile(list.get(list.size() - 1).getTemplateFileName(), list.get(list.size() - 1).getTemplateFileId());
        return ReplaceWordUtil.operateWord(data, picData, file, list.get(list.size() - 1).getTemplateFileName());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void uploadAndUpdate(String orderId) {
        LoginUser currentUser = LoginHelper.getLoginUser();
        if (ObjectUtil.isEmpty(currentUser)) {
            throw new ApiException("登录过期，请重新登录");
        }
        /**
         * 1、文件填充
         */
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new ApiException("当前订单不存在");
        }
        OrderContract byOrderCode = orderContractService.getByOrderCode(order.getOrderCode());
        if (byOrderCode != null) {
            throw new ApiException("当前订单已有合同存在，请勿重复签署");
        }

        FileItem fileItem = fillContract(order, null);


        if (fileItem != null) {
            //TODO 2、上传填充好的文件
            String contractFileId = String.valueOf(sysOssService.upload(fileItem.getData(), fileItem.getFileName(), fileItem.getContentType()).getOssId());
            File contractFile = null;
            if (fileItem.getFileName() != null) {
                contractFile = new File(fileItem.getFileName());
                try {
                    FileUtils.writeByteArrayToFile(contractFile, fileItem.getData());
                } catch (IOException e) {
                    log.error("multipartFile转File失败");
                    throw new ApiException("文件类型转换失败");
                }
            }
            //TODO 3、上传填充好的文件到法大大平台
            FileUploadRequest fileUploadRequest = new FileUploadRequest();
            if (contractFile != null) {
                fileUploadRequest.setFile(contractFile);
            } else {
                throw new ApiException("文件不存在");
            }
            fileUploadRequest.setFileName(order.getEnterpriseName()
                + "与"
                + order.getBordererInfoName()
                + order.getProductNumber()
                + "购销合同" + ".docx");
            //上传填充好的合同文件到法大大平台
            String uploadFileId = fddService.upload(fileUploadRequest);

            //TODO 4、更新订单与合同关联信息
            //查询订单信息
            //获取发起人（企业方）的信息
            Account originAccount = fddService.getAccountByMobile(currentUser.getMobile());
            if (originAccount == null) {
                throw new ApiException("当前用户未在法大大平台注册");
            }
            //获取企业信息
            Company company = fddService.getCompanyByCompanyName(order.getEnterpriseName());
            if (company == null) {
                throw new ApiException("当前企业未在法大大平台注册");
            }
            //获取边民信息
            BordererInfo bordererInfo = bordererInfoService.getBordererInfoById(order.getBordererInfoId());
            if (bordererInfo == null) {
                throw new ApiException("当前边民信息不存在");
            }
            //边民在法大大平台的信息
            Account borderAccount = fddService.getAccountByMobile(bordererInfo.getPhoneNumber());
            if (borderAccount == null) {
                throw new ApiException("当前用户未在法大大平台注册");
            }


            //TODO 5、更新FileId到订单与合同关联表中
            OrderContract orderContract = new OrderContract();
            //orderId
            orderContract.setOrderCode(order.getOrderCode());
            orderContract.setOrderId(order.getId());
            orderContract.setUploadFileId(uploadFileId);
            //填充后的文件id
            orderContract.setContractId(IdUtil.getSnowflakeNextIdStr());
            //填充后的文件FileId
            orderContract.setContractFileId(contractFileId);

            //公司和人员信息
            //边民
            orderContract.setBordererInfoId(order.getBordererInfoId());
            orderContract.setBordererAccountId(borderAccount.getAccountId());
            //企业签署人信息
            orderContract.setReceiverAccountId(originAccount.getAccountId());
            orderContract.setReceiverId(currentUser.getUserCode());
            //企业信息
            orderContract.setCompanyId(order.getEnterpriseId());
            orderContract.setCompanyAccountId(company.getCompanyId());
            //签署状态
            orderContract.setCompanySign(SignStatusEum.UNSIGNED.getStatus());
            orderContract.setBordererSign(SignStatusEum.UNSIGNED.getStatus());
            //总状态
            orderContract.setSignStatus(SignStatusEum.UNSIGNED.getStatus());
            orderContractMapper.insertOrUpdate(orderContract);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean createAndPush(String orderCode, String orderId, String authSignStatus) {
        OrderContract orderContract = orderContractService.getByOrderCode(orderCode);
        if (orderContract == null) {
            return false;
        }

        LoginUser currentUser = LoginHelper.getLoginUser();

        //发起方个人信息[企业]
        Account loginUserAccount = fddService.getAccountByMobile(currentUser.getMobile());

        //发起方公司信息（当前登录系统）
        Enterprise enterprise = enterpriseService.getEntityByLoginUser();
        if (enterprise == null) {
            throw new ApiException("当前用户身份不是企业用户");
        }
        Company originCompany = fddService.getCompanyByCompanyName(enterprise.getEnterpriseName());

        //企业信息[甲方]
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new ApiException("当前订单不存在");
        }
        Company partyACompany = fddService.getCompanyByCompanyName(order.getEnterpriseName());

        if (partyACompany == null) {
            throw new ApiException("当前企业未在法大大平台注册，请注册后再下单");
        }

        //查询甲方、乙方是否开启自动签

        SeachUnwantedAuthSignRequest borderAuthSign = new SeachUnwantedAuthSignRequest();
        borderAuthSign.setAuthorizerFlag(AuthTypeEnum.BORDERER.getType());
        borderAuthSign.setAuthorizerTargetId(orderContract.getBordererAccountId());
        UnwantedAuthSignStatusResponse borderAuthSignResponse = fddService.searchUnwantedAuthSignStatus(borderAuthSign);
        String borderAuthSignStatus = EnableEnum.DISABLE.getStatus();
        if (borderAuthSignResponse != null && NumberUtil.equals(borderAuthSignResponse.getStatus(), UnwantedAuthSignEnum.EFFECT.getType())) {
            borderAuthSignStatus = EnableEnum.ENABLE.getStatus();
        }


        CreateAndPushRequest createAndPushRequest = new CreateAndPushRequest();

        createAndPushRequest.setDocTitle("订单" + order.getOrderCode());

        List<CreateAndPushRequest.Doc> docs = new ArrayList<>();
        CreateAndPushRequest.Doc doc = null;

        List<String> uploadFileIdList = Arrays.stream(orderContract.getUploadFileId().split(",")).collect(Collectors.toList());
        for (String uploadFileId : uploadFileIdList) {
            doc = new CreateAndPushRequest.Doc();
            doc.setFileId(uploadFileId);
            docs.add(doc);
        }

        createAndPushRequest.setDocList(docs);
        createAndPushRequest.setSenderAccountId(loginUserAccount.getAccountId());
        createAndPushRequest.setCompanyId(originCompany.getCompanyId());
        createAndPushRequest.setIsAutoArchive(1);
        createAndPushRequest.setExpireDate(DateUtil.format(DateUtil.offsetDay(new Date(), 2), "yyyy-MM-dd"));
        createAndPushRequest.setSignDeadline(DateUtil.format(DateUtil.offsetDay(new Date(), 2), "yyyy-MM-dd"));
        //签署方列表
        List<CreateAndPushRequest.SignerInfo> signerInfos = new ArrayList<>();

        CreateAndPushRequest.SignerInfo signerInfo = null;
        for (int i = 0; i < 2; i++) {
            String notifyNo = IdUtil.getSnowflakeNextIdStr();
            signerInfo = new CreateAndPushRequest.SignerInfo();
            signerInfo.setNotifyNo(notifyNo);
            signerInfo.setIsPosition(1);
            signerInfo.setIsSendNotify(1);
            signerInfo.setPriority(0);
            //仅signMode为0时，支持免验证签。
            signerInfo.setSignMode(0);
            //有效期设置为 一小时
            signerInfo.setUrlTimeOut(60);
            //边民
            if (i == 0) {
                //0：门户手动签署（默认）；1：系统免验证签；2：手动免验证签。
                if (borderAuthSignStatus.equals(EnableEnum.ENABLE.getStatus())) {
                    signerInfo.setSignType(2);
                }
                signerInfo.setSignerAccountId(orderContract.getBordererAccountId());

                List<DocSignInfoDTO> docSignInfoDTOS = new ArrayList<>();

                DocSignInfoDTO docSignInfoDTO = new DocSignInfoDTO();
                docSignInfoDTO.setFileId(orderContract.getUploadFileId());
                DocSignInfoDTO.PersonSealDTO personSealDTO = new DocSignInfoDTO.PersonSealDTO();
                personSealDTO.setKeyWord("卖方");
                personSealDTO.setKeyWordPolicy(2);
                personSealDTO.setOffsetX(8.0);
                personSealDTO.setOffsetY(13.0);

                docSignInfoDTO.setPersonSealDTO(personSealDTO);
                docSignInfoDTOS.add(docSignInfoDTO);
                signerInfo.setDocSignInfoDTO(docSignInfoDTOS);
                String parentOrderId = StrUtil.blankToDefault(order.getParentOrderId(), order.getId());
                signerInfo.setReturnUrl(ReturnUrlUtil.getBordererOrderContractUrl(returnUrlPrefix, parentOrderId, order.getProductId(), order.getOrderStatus()));
                orderContract.setBordererSignNotify(notifyNo);
            }
            //企业
            if (i == 1) {
                //0：门户手动签署（默认）；1：系统免验证签；2：手动免验证签。
                if (authSignStatus.equals(EnableEnum.ENABLE.getStatus())) {
                    signerInfo.setSignType(2);
                }
                signerInfo.setSignerAccountId(orderContract.getReceiverAccountId());
                //企业签
                signerInfo.setCompanyId(partyACompany.getCompanyId());
                signerInfo.setSignDemand(1);

                List<DocSignInfoDTO> docSignInfoDTOS = new ArrayList<>();

                DocSignInfoDTO docSignInfoDTO = new DocSignInfoDTO();
                docSignInfoDTO.setFileId(orderContract.getUploadFileId());

                ArrayList<DocSignInfoDTO.CompanySeal> companySeals = new ArrayList<>();
                DocSignInfoDTO.CompanySeal companySeal = new DocSignInfoDTO.CompanySeal();
                companySeal.setKeyWord("买方");
                companySeal.setKeyWordPolicy(2);
                companySeal.setOffsetX(8.0);
                companySeal.setOffsetY(110.0);

                companySeals.add(companySeal);
                docSignInfoDTO.setCompanySealDTO(companySeals);

                docSignInfoDTOS.add(docSignInfoDTO);
                signerInfo.setDocSignInfoDTO(docSignInfoDTOS);
                String parentOrderId = StrUtil.blankToDefault(order.getParentOrderId(), order.getId());
                signerInfo.setReturnUrl(ReturnUrlUtil.getEnterpriseOrderContractUrl(returnUrlPrefix, parentOrderId, order.getProductId(), order.getQuantityUnit()));
                orderContract.setCompanySignNotify(notifyNo);
            }
            signerInfos.add(signerInfo);

        }
        createAndPushRequest.setSignerInfos(signerInfos);
        log.info("创建签署推送请求参数" + JSONObject.toJSONString(createAndPushRequest));
        CreateAndPushResponse andPush = fddService.createAndPush(createAndPushRequest, "/updateSignStatus");
        log.info("创建签署推送返回结果" + JSONObject.toJSONString(andPush));
        if (ObjectUtil.isNotEmpty(andPush)) {
            //更新订单合同关联表信息
            orderContract.setDocId(andPush.getDocId());
            orderContractMapper.insertOrUpdate(orderContract);
        } else {
            return false;
        }

        return true;
    }

    @Override
    public int getNeedHandler() {
        LoginUser currentUser = LoginHelper.getLoginUser();
        if (UserTypeEnum.PLATFORM.equalsType(currentUser.getUserType())) {
            return orderMapper.selectNeedHandler(currentUser.getUserCode()).size();
        } else {
            return orderMapper.selectAllNeedHandler().size();
        }
    }

    private Enterprise getEnterprise(String userCode) {
        return enterpriseService.getEnterpriseByUserCode(userCode);
    }

    @Override
    public int getEnterpriseNeedHandler() {
        LoginUser currentUser = LoginHelper.getLoginUser();
        Enterprise enterprise = getEnterprise(currentUser.getUserCode());
        if (enterprise == null) {
            return 0;
        }
        return orderMapper.selectEnterpriseNeedHandler(enterprise.getId()).size();
    }

    @Override
    public int getBordererNeedHandler() {
        LoginUser currentUser = LoginHelper.getLoginUser();
        BordererInfo bordererInfo = bordererInfoService.getBordererInfoByUserCode(currentUser.getUserCode());
        if (bordererInfo == null) {
            return 0;
        }
        return orderMapper.selectBordererNeedHandler(bordererInfo.getId()).size();
    }

    private String previewPdf(OrderContract orderContract) {
        String upload = fddService.uploadPfd(orderContract.getDocId());
        String contractFileId = orderContract.getContractFileId();
        if (StrUtil.isBlank(upload)) {
            return contractFileId;
        }
        orderContract.setContractFileId(upload);
        orderContractMapper.updateById(orderContract);
        return upload;
    }

    @Override
    public void getContractPageView(String orderCode, HttpServletResponse response) {
        OrderContract orderContract = orderContractService.getByOrderCode(orderCode);
        if (ObjectUtil.isEmpty(orderContract)) {
            throw new ApiException("当前订单合同未生成");
        }
        if (orderContract.getDocId() == null) {
            throw new ApiException("当前合同未生成，请稍后重试");
        }
        String pageViewFileId = previewPdf(orderContract);
        if (StrUtil.isBlank(pageViewFileId)) {
            throw new ApiException("预览失败");
        }
        sysOssService.preview(pageViewFileId, response);
    }

    @Override
    public String getDoc(String orderCode) {
        OrderContract orderContract = orderContractService.getByOrderCode(orderCode);
        if (ObjectUtil.isEmpty(orderContract)) {
            throw new ApiException("当前订单合同未生成");
        }

        if (orderContract.getDocId() == null) {
            throw new ApiException("当前合同未生成，请稍后重试");
        }

        DocDownloadRequest docDownloadRequest = new DocDownloadRequest();
        docDownloadRequest.setDocId(orderContract.getDocId());
        DocDownloadResponse download = fddService.download(docDownloadRequest);
        if (download != null) {
            return download.getFileUrl();
        }
        throw new ApiException("当前订单合同文件下载失败");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<String> placeOrder(PlaceOrderRequest request) {
        LoginUser currentUser = LoginHelper.getLoginUser();

        ArrayList<String> orderCodes = new ArrayList<>();

        Set<String> checkNumSet = new HashSet<>();
        // 存放总商品的总订单
        Map<String, PlaceOrder> placeOrderHashMap = new HashMap<>();

        // 购买商品的企业
        Enterprise enterprise = enterpriseService.getEnterpriseByUserCode(currentUser.getUserCode());
        if (ObjectUtil.isNull(enterprise)) {
            throw new ApiException("非企业用户，禁止当前操作!");
        }

        ContractTemplate contractTemplate = new ContractTemplate();
        contractTemplate.setTemplateType("0");
        contractTemplate.setTemplateStatus(ContractStatusEnum.USING.getStatus());
        List<ContractTemplate> list = contractTemplateService.queryList(contractTemplate);
        if (CollUtil.isEmpty(list)) {
            throw new ApiException("请联系管理员上传购销合同模板");
        }
        String parentProductId = request.getIds().get(0);
        List<Product> children = productService.findByParentProductId(parentProductId);
        children.forEach(product -> {
            if (!CharSequenceUtil.equals(product.getAuditStatus(), AuditStatusEnum.SUCCESS.getStatus())) {
                throw new ApiException("商品没有审核通过!");
            }

            if (CharSequenceUtil.equals(product.getSale(), EnableEnum.DISABLE.getStatus())) {
                throw new ApiException("商品未上架!");
            }

            checkNumSet.add(product.getProductCostId());
            if (checkNumSet.size() > 1) {
                throw new ApiException("商品编号不一致!");
            }

            if (ProductSaleStatus.PLACE_ORDER.equalsStatus(product.getSale())) {
                throw new ApiException("商品已下单!");
            }

            if (ProductSaleStatus.SOLD.equalsStatus(product.getSale())) {
                throw new ApiException("商品已出售!");
            }

            if (ProductGroupEnum.CHILD.equalsStatus(product.getGroupStatus())) {
                if (CharSequenceUtil.isNotBlank(product.getParentProductId())) {
                    PlaceOrder placeOrder = placeOrderHashMap.get(product.getParentProductId());
                    if (placeOrder == null) {
                        Product parentProduct = productMapper.selectById(product.getParentProductId());
                        parentProduct.setQuantity("0");
                        parentProduct.setPrice("0");
                        parentProduct.setRealPrice("0");
                        placeOrder = new PlaceOrder(parentProduct);
                        placeOrderHashMap.put(parentProduct.getId(), placeOrder);
                    }

                    placeOrder.getChildrenList().add(product);

                    Product parentProduct = placeOrder.getParentProduct();
                    // 计算总订单的总数量
                    BigDecimal quantity = new BigDecimal(parentProduct.getQuantity()).add(new BigDecimal(product.getQuantity()));
                    parentProduct.setQuantity(ProductCalculateUtils.stripTrailingZerosString(quantity));
                    // 计算总订单的总金额
                    BigDecimal price = new BigDecimal(parentProduct.getPrice()).add(new BigDecimal(product.getPrice()));
                    BigDecimal realPrice = new BigDecimal(parentProduct.getRealPrice()).add(new BigDecimal(product.getRealPrice()));
                    parentProduct.setPrice(price.toString());
                    parentProduct.setRealPrice(realPrice.toString());
                    // 计算总订单的总服务费
                    BigDecimal taxation = ProductCalculateUtils.calculateTaxation(realPrice);
                    BigDecimal serviceCharge = ProductCalculateUtils.calculateServiceCharge(taxation);
                    BigDecimal profit = realPrice.subtract(price).subtract(taxation).subtract(serviceCharge);

                    parentProduct.setTaxation(taxation);
                    parentProduct.setServiceCharge(serviceCharge);
                    parentProduct.setProfit(profit);
                } else {
                    throw new ApiException("子商品的 parentId 不能为空!");
                }
            }
        });

        placeOrderHashMap.forEach((s, placeOrder) -> {
            Product parentProduct = placeOrder.getParentProduct();
            Order parentOrder = buildOrder(request, enterprise, parentProduct);
            orderMapper.insert(parentOrder);
            RedisUtils.setCacheObject(RedisKey.BORDERER_SIGN_CONTRACT.createRedisKey(parentOrder.getId()), placeOrder.getChildrenList().size());
            RedisUtils.setCacheObject(RedisKey.ENTERPRISE_SIGN_CONTRACT.createRedisKey(parentOrder.getId()), placeOrder.getChildrenList().size());
            appendCarNumber(parentOrder.getId(), request.getCarNumbers());
            parentProduct.setSale(ProductSaleStatus.PLACE_ORDER.getStatus());
            productMapper.updateById(parentProduct);

            sendEnterMessage(parentOrder, currentUser);

            for (int i = 0; i < placeOrder.getChildrenList().size(); i++) {
                int number = i + 1;
                Product childProduct = placeOrder.getChildrenList().get(i);
                Order childOrder = buildOrder(request, enterprise, childProduct);
                childOrder.setOrderCode(parentOrder.getOrderCode() + "-" + number);
                childOrder.setParentOrderId(parentOrder.getId());
                orderMapper.insert(childOrder);
                orderCodes.add(childOrder.getId());
                childProduct.setSale(ProductSaleStatus.PLACE_ORDER.getStatus());
                productMapper.updateById(childProduct);
            }
        });
        OrderBatchBo batchRequest = new OrderBatchBo();
        batchRequest.setEnable(true);
        batchRequest.setIds(orderCodes);
        return signOrder(batchRequest);
    }

    /**
     * 发送企业签署通知
     *
     * @param order
     * @param currentUser
     */
    private void sendEnterMessage(Order order, LoginUser currentUser) {
        messageService.insertMessage(MessageCategoryEnum.ENTERPRISE_SIGN, order.getId(), "新的订单待签署", "订单编号:" + order.getId() + "待签署", currentUser.getUserCode());
    }

    private void appendCarNumber(String orderId, List<String> carNumbers) {
        if (CollUtil.isNotEmpty(carNumbers)) {
            for (String carNumber : carNumbers) {
                carNumberService.save(orderId, CarNumberBusinessTypeEnum.ORDER.getType(), carNumber);
            }
        }
    }

    private Order buildOrder(PlaceOrderRequest request, Enterprise enterprise, Product product) {
        Order order = new Order();
        // 订单基础信息
        order.setId(IdUtil.getSnowflakeNextIdStr());
        order.setOrderCode(order.getId());
        order.setReceiverName(request.getReceiverName());
        order.setReceiverPhone(request.getReceiverPhone());
        order.setReceiverAddress(request.getReceiverAddress());
        order.setReceiverTime(request.getReceiverTime());
        // 和订单关联的商品信息
        order.setProductId(product.getId());
        order.setProductNumber(product.getNumber());
        order.setProductTitle(product.getTitle());
        order.setProductDataType(product.getProductCostCategory());
        order.setProductDataName(product.getProductCostName());
        order.setDeclarationNumber(product.getDeclarationNumber());
        order.setBordererInfoId(product.getBordererInfoId());
        order.setBordererInfoName(product.getBordererInfoName());
        order.setQuantityUnit(product.getQuantityUnit());
        order.setMeasureUnit(product.getMeasureUnit());
        order.setProductPoster(product.getPosterList());
        order.setProductSpecification(product.getSpecification());
        // 格式化数字参数
        order.setProductQuantity(ProductCalculateUtils.stripTrailingZerosString(product.getTotalQuantity()));
        order.setAmount(ProductCalculateUtils.stripTrailingZerosString(product.getTotalRealPrice()));
        order.setCost(ProductCalculateUtils.stripTrailingZerosString(product.getTotalPrice()));
        order.setTaxation(ProductCalculateUtils.stripTrailingZeros(product.getTaxation()));
        order.setServiceCharge(ProductCalculateUtils.stripTrailingZeros(product.getServiceCharge()));
        order.setProfit(ProductCalculateUtils.stripTrailingZeros(product.getProfit()));


        order.setParentProductId(product.getParentProductId());
        order.setBorderGroupId(product.getBorderGroupId());
        order.setBorderAgentId(product.getBorderAgentId());
        order.setBorderAgentName(product.getBorderAgentName());
        order.setGroupStatus(product.getGroupStatus());

        order.setBorderAgentCardNumber(product.getBorderAgentCardNumber());
        order.setBordererInfoCardNumber(product.getBordererInfoCardNumber());

        // 购买商品的企业信息
        order.setEnterpriseId(enterprise.getId());
        order.setEnterpriseCode(enterprise.getEnterpriseCode());
        order.setEnterpriseName(enterprise.getEnterpriseName());

        order.setBorderIdCardNumber(product.getBorderIdCardNumber());
        order.setBorderPhoneNumber(product.getBorderPhoneNumber());

        order.setCompanySign(EnableEnum.DISABLE.getStatus());
        order.setBordererSign(EnableEnum.DISABLE.getStatus());
        order.setOrderStatus(OrderStatus.WAIT_SIGN.getStatus());
        order.setBordererGroup(product.getBordererGroup());
        return order;
    }

    @Override
    public String getSignUrl(String orderCode) {
        //
        OrderContract orderContract = orderContractService.getByOrderCode(orderCode);

        //创建（乙方）边民用户获取文档签署链接请求对象
        FileGetSignRepeatRequest bordererSignRequest = new FileGetSignRepeatRequest();
        bordererSignRequest.setNotifyNo(orderContract.getBordererSignNotify());
        bordererSignRequest.setDocId(orderContract.getDocId());
        bordererSignRequest.setSignerAccountId(orderContract.getBordererAccountId());

        String borderSignUrl = fddService.getSignUrl(bordererSignRequest);
        orderContract.setBorderSignUrl(borderSignUrl);


        //创建(甲方)企业用户获取文档签署链接请求对象
        FileGetSignRepeatRequest companyFileSignRequest = new FileGetSignRepeatRequest();
        companyFileSignRequest.setNotifyNo(orderContract.getCompanySignNotify());
        companyFileSignRequest.setDocId(orderContract.getDocId());
        companyFileSignRequest.setSignerAccountId(orderContract.getReceiverAccountId());

        String companySignUrl = fddService.getSignUrl(companyFileSignRequest);
        orderContract.setCompanySignUrl(companySignUrl);
        orderContractMapper.updateById(orderContract);

        LoginUser currentUser = LoginHelper.getLoginUser();
        if (StrUtil.equals(UserTypeEnum.BORDERER.getUserType(), currentUser.getUserType())) {
            //边民
            return borderSignUrl;
        } else if (StrUtil.equals(UserTypeEnum.ENTERPRISE.getUserType(), currentUser.getUserType())) {
            //企业用户
            return companySignUrl;
        }
        //返回边民签署链接
        return null;
    }

    private List<Order> findByParentOrderId(String id) {
        return orderMapper.selectList(Wrappers.lambdaQuery(Order.class).eq(Order::getParentOrderId, id));
    }

    private AppOrderResult buildAppOrderRequest(Order order) {
        LoginUser currentUser = LoginHelper.getLoginUser();
        AppOrderResult result = BeanUtil.toBean(order, AppOrderResult.class);
        OrderContract orderContract = orderContractService.getByOrderCode(order.getOrderCode());
        if (ObjectUtil.isNotEmpty(orderContract)) {
            if (StrUtil.equalsAny(currentUser.getUserType(), UserTypeEnum.BORDERER.getUserType(), UserTypeEnum.BORDERER_AGENT.getUserType())) {
                if (orderContract.getBorderSignUrl() != null) {
                    result.setContractStatus(0);
                    result.setBorderSignUrl(orderContract.getBorderSignUrl());
                }
            } else if (currentUser.getUserType().equals(UserTypeEnum.ENTERPRISE.getUserType())) {
                if (orderContract.getCompanySignUrl() != null) {
                    result.setContractStatus(0);
                    result.setCompanySignUrl(orderContract.getCompanySignUrl());
                }
            }
        }
        if (CharSequenceUtil.isBlank(order.getCost())) {
            BigDecimal amount = new BigDecimal(order.getAmount());
            BigDecimal cost = amount.subtract(order.getTaxation()).subtract(order.getServiceCharge()).subtract(order.getProfit());
            result.setCost(cost.toString());
        }
        result.setBordererCarNumbers(getBordererCarNumbers(order));
        result.setEnterpriseCarNumbers(getEnterpriseCarNumbers(order));
        return result;
    }

    private List<String> getBordererCarNumbers(Order order) {
        String productId;
        if (StrUtil.isNotBlank(order.getParentProductId())) {
            productId = order.getParentProductId();
        } else {
            productId = order.getProductId();
        }
        return carNumberService.list(productId, CarNumberBusinessTypeEnum.PRODUCT.getType()).stream().map(CarNumber::getCarNumber).collect(Collectors.toList());
    }

    private List<String> getEnterpriseCarNumbers(Order order) {
        String orderId;
        if (StrUtil.isNotBlank(order.getParentOrderId())) {
            orderId = order.getParentOrderId();
        } else {
            orderId = order.getId();
        }
        return carNumberService.list(orderId, CarNumberBusinessTypeEnum.ORDER.getType()).stream().map(CarNumber::getCarNumber).collect(Collectors.toList());
    }


    @Override
    public List<AppOrderResult> getChildren(DetailBo request) {
        List<Order> orderList = findByParentOrderId(request.getId());

        List<AppOrderResult> resultList = new ArrayList<>();
        orderList.forEach(item -> resultList.add(buildAppOrderRequest(item)));

        return resultList;
    }

    @Override
    public AppOrderResult getOrderDetail(DetailBo request) {
        Order order = orderMapper.selectById(request.getId());
        AppOrderResult result = buildAppOrderRequest(order);
        if (ProductGroupEnum.PARENT.equalsStatus(order.getGroupStatus())) {
            result.setChildrenOrder(getChildren(request));
            result.setChildrenProduct(productService.findVoByParentProductId(order.getParentProductId()));
        } else {
            result.setBordererCarNumbers(carNumberService.list(order.getProductId(), CarNumberBusinessTypeEnum.PRODUCT.getType()).stream().map(CarNumber::getCarNumber).collect(Collectors.toList()));
            result.setEnterpriseCarNumbers(carNumberService.list(order.getId(), CarNumberBusinessTypeEnum.ORDER.getType()).stream().map(CarNumber::getCarNumber).collect(Collectors.toList()));
        }
        if (StrUtil.equals(order.getOrderStatus(), OrderStatus.WAIT_PAY.getStatus())) {
            result.setExpireTime(RedisUtils.getTimeToLive(RedisKey.PAY_ORDER.createRedisKey(order.getId())) / 1000L);
        }
        return result;
    }

    @Override
    public Page<AppOrderResult> getAgentOrderHistory(AgainHistoryByPageReq request) {
        LoginUser currentUser = LoginHelper.getLoginUser();
        // 获取边民信息
        BordererInfo bordererInfo = bordererInfoService.getBordererInfoByUserCode(currentUser.getUserCode());

        Order order = new Order();
        order.setGroupStatus(ProductGroupEnum.CHILD.getStatus());

        if (UserTypeEnum.BORDERER_AGENT.equalsType(currentUser.getUserType())) {
            order.setBordererInfoId(request.getBorderId());
            order.setBorderAgentId(bordererInfo.getId());
        } else if (UserTypeEnum.BORDERER.equalsType(currentUser.getUserType())) {
            // 获取边民和边民代表的关联信息
            BorderAgent borderAgent = borderAgentMapper.selectOne(new LambdaQueryWrapper<BorderAgent>()
                .eq(BorderAgent::getBordererId, bordererInfo.getId())
                .eq(BorderAgent::getApplyStatus, AgentApplyStatusEnum.AGREE.getStatus()));

            order.setBordererInfoId(bordererInfo.getId());
            order.setBorderAgentId(borderAgent.getAgentBordererId());
        }
        Page<Order> orderPage = orderMapper.selectPage(request.build(), buildLambdaQueryWrapper(order));
        return packageOrderPage(orderPage);
    }

    private Page<AppOrderResult> packageOrderPage(Page<Order> orderPage) {
        List<AppOrderResult> resultList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderPage.getRecords())) {
            orderPage.getRecords().forEach(item -> {
                AppOrderResult orderResult = buildAppOrderRequest(item);
                if (ProductGroupEnum.PARENT.equalsStatus(item.getGroupStatus())) {
                    DetailBo detailRequest = new DetailBo();
                    detailRequest.setId(item.getId());
                    List<AppOrderResult> children = getChildren(detailRequest);
                    orderResult.setChildrenOrder(children);

                    StringBuilder stringBuilder = new StringBuilder();
                    for (AppOrderResult child : children) {
                        stringBuilder.append(child.getBordererInfoName()).append(",");
                    }

                    String borderName = stringBuilder.substring(0, stringBuilder.lastIndexOf(","));
                    orderResult.setBordererInfoName(borderName);
                }

                resultList.add(orderResult);
            });
        }

        Page<AppOrderResult> result = new Page<>(orderPage.getCurrent(), orderPage.getSize(), orderPage.getTotal());
        result.setRecords(resultList);
        return result;
    }

    @Override
    public List<CheckSelectResp> checkOrderSelect(List<CheckSelectReq> checkSelectReqs) {
        Map<String, List<String>> checkSelectReqMap = new HashMap<>();
        checkSelectReqs.forEach(item -> {
            List<String> childrenIds = checkSelectReqMap.get(item.getParentId());
            if (CollectionUtil.isEmpty(childrenIds)) {
                childrenIds = new ArrayList<>();
                checkSelectReqMap.put(item.getParentId(), childrenIds);
            }
            childrenIds.add(item.getId());
        });

        List<CheckSelectResp> resultOrders = new ArrayList<>();
        checkSelectReqMap.forEach((parentId, ids) -> {
            QueryOrderBo bo = new QueryOrderBo();
            bo.setParentOrderId(parentId);
            bo.setIds(ids);

            List<AppOrderResult> appOrderResultList = orderMapper.selectList(buildLambdaQueryWrapper(bo)).stream().map(this::buildAppOrderRequest).collect(Collectors.toList());

            if (CollectionUtil.isNotEmpty(appOrderResultList)) {
                CheckSelectResp checkSelectResp = new CheckSelectResp();
                checkSelectResp.setParentId(parentId);
                checkSelectResp.setOrderResults(appOrderResultList);
                resultOrders.add(checkSelectResp);
            }
        });

        return resultOrders;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void cancelOrder(String orderId) {
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new ApiException("该订单不存在");
        }
        if (CharSequenceUtil.equals(OrderStatus.CANCEL.getStatus(), order.getOrderStatus())) {
            throw new ApiException("订单已取消!");
        }
        if (ProductGroupEnum.CHILD.equalsStatus(order.getGroupStatus())) {
            throw new ApiException("子订单禁止取消!");
        }
        if (StrUtil.equalsAny(order.getOrderStatus(), OrderStatus.WAIT_TAKE_OVER.getStatus(), OrderStatus.TAKE_OVER.getStatus(), OrderStatus.COMPLETE.getStatus())) {
            throw new ApiException("企业已付款，该订单无法被取消");
        }
        order.setOrderStatus(OrderStatus.CANCEL.getStatus());
        orderMapper.insertOrUpdate(order);
        updateProductStatus(order.getProductId(), ProductSaleStatus.SALE);
        List<Order> children = findByParentOrderId(orderId);
        if (CollUtil.isNotEmpty(children)) {
            for (Order child : children) {
                child.setOrderStatus(OrderStatus.CANCEL.getStatus());
                orderMapper.insertOrUpdate(child);
                updateProductStatus(child.getProductId(), ProductSaleStatus.SALE);
            }
        }
        messageService.completeMessage(MessageCategoryEnum.BORDER_SIGN, orderId);
    }

    @Override
    public List<OrderSettlement> getOrderSettlements(String orderId) {
        return orderSettlementMapper.selectList(Wrappers.lambdaQuery(OrderSettlement.class).eq(OrderSettlement::getOrderId, orderId));
    }

    /**
     * 更改订单ID
     *
     * @param productId
     * @param status
     */
    private void updateProductStatus(String productId, ProductSaleStatus status) {
        Product product = productMapper.selectById(productId);
        if (ObjectUtil.isNotNull(product)) {
            product.setSale(status.getStatus());
            productMapper.updateById(product);
        }
    }
}
